//
//  ZZCameraTool.m
//  iOS照相机
//
//  Created by upintech on 17/5/13.
//  Copyright © 2017年 ZZMo. All rights reserved.
//

#import "ZZCameraTool.h"
#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>

#define kDevicedNotSupper @"该设备不支持"
#define KUserStatusDenied @"用户禁止访问"
#define kCameraToolKey @"kCameraToolKey"

@interface ZZCameraTool ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate>

@property (nonatomic, strong) UIImagePickerController *imagePickerController;

// 返回选中的图片和错误
@property (nonatomic, copy) void(^result)(id obj,NSError *error);

// 用来modal的控制器
@property (nonatomic, weak) UIViewController *presentController;

// model完成之后的动作
@property (nonatomic, copy) void(^completion)();

@property (nonatomic, strong) PHImageRequestOptions *options;
// 图片数组
@property (nonatomic, strong) PHFetchResult *assets;

// 每张图片执行的block
@property (nonatomic, copy) void (^ __nullable imageBlock)( UIImage * __nullable obj , NSUInteger idx, BOOL  * __nullable stop);

@property (nonatomic, copy) void(^failed)();

@property (nonatomic, strong) NSError *error;

@property (nonatomic,strong) MBProgressHUD *hud;

@end

@implementation ZZCameraTool

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    
    static id tool = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        
        tool = [super allocWithZone:zone];
    });
    
    return tool;
}

#pragma mark - Func
#pragma mark - Public Func
- (void)showcamera:(UIViewController *)controlller result:(void(^ __nullable)(UIImage * __nullable image,NSError * __nullable error))result {
    
    self.presentController = controlller;
    self.result = result;
    // 判断设备是否可用
    if(![self isCameraAvailable]) {
        
        NSError *error = [NSError errorWithDomain:@"" code:3001 userInfo:@{@"message":kDevicedNotSupper}];
        self.error = error;
        result(nil,error);
        NSLog(@"%@",error);
        return;
    };
    
    // 判断权限
    [self getCameraAuthorization:^(BOOL granted) {
        
        if (granted) { // 如果有权限
            
            [self useCamera];
        } else {
            
            NSError *error = [NSError errorWithDomain:@"" code:3002 userInfo:@{@"message":KUserStatusDenied}];
            self.error = error;
            result(nil,error);
        }
    }];
    
    // 请求设备授权
//    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { // 就算设备不支持也会弹出是否授权的框}];
}

- (void)userPhotoLibrary:(UIViewController *__nullable)controller result:(void(^ __nullable)(UIImage * __nullable image,NSError * __nullable error))result {
    
    // 判断相册是否可用
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        
        if (status == PHAuthorizationStatusAuthorized) {
            
            self.presentController = controller;
            
            self.result = result;
            
            // 判断是否可以打开相册
            if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
                
                self.error = [NSError errorWithDomain:@"" code:3001 userInfo:@{@"message":kDevicedNotSupper}];
                NSLog(@"%@",self.error);
                return;
            };
            
            // 可以打开相册
            UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
            ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
            
            ipc.delegate = self;
            [self.presentController presentViewController:ipc animated:YES completion:nil];
            
        } else { // 没有权限
            
            NSError *error = [NSError errorWithDomain:@"" code:3002 userInfo:@{@"message":KUserStatusDenied}];
            self.error = error;
            NSLog(@"%@",error);
        }
    }];
}

// 相册和视频
- (void)userPhotoAndVideo:(UIViewController *__nullable)controller result:(void(^ __nullable)(id __nullable result,NSError * __nullable error))result {
    
    // 判断相册是否可用
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        
        if (status == PHAuthorizationStatusAuthorized) {
            
            self.presentController = controller;
            
            self.result = result;
            
            // 判断是否可以打开相册
            if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
                
                self.error = [NSError errorWithDomain:@"" code:3001 userInfo:@{@"message":kDevicedNotSupper}];
                NSLog(@"%@",self.error);
                return;
            };
            
            // 可以打开相册
            UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
            ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

//            ipc.mediaTypes = [[NSArray alloc] initWithObjects:(NSString *)kUTTypeImage,(NSString *)kUTTypeJPEG,(NSString *)kUTTypePNG,(NSString*) kUTTypeMovie, (NSString*) kUTTypeVideo, nil];
            
            ipc.delegate = self;
            [self.presentController presentViewController:ipc animated:YES completion:nil];
            
        } else { // 没有权限
            
            NSError *error = [NSError errorWithDomain:@"" code:3002 userInfo:@{@"message":KUserStatusDenied}];
            self.error = error;
            NSLog(@"%@",error);
        }
    }];
   
    
}

// 访问相册
- (void)enumerateObjectsUsingBlock:(void (^ __nullable)( UIImage * __nullable obj , NSUInteger idx, BOOL  * __nullable stop))block failed:(void(^ __nullable)(NSError * __nullable error))failed {
    
    // 获取访问相册权限
    [self usePhoto];
    
    self.imageBlock = block;
    self.failed = failed;
}

// 获取照相机权限
- (void)getCameraAuthorization:(void(^)(BOOL granted))result {
    
    [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { // 就算设备不支持也会弹出是否授权的框
        
        result(granted);
    }];
    
    
}

// 获取相册权限
- (void)getPhotoAuthorization:(void(^)(PHAuthorizationStatus status))result {
    
    
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        
        result(status);
    }];
    
}

#pragma mark - Private Func
- (void)useCamera {
    
    // 把self绑定到当前线程
    
    //创建UIImagePickerController对象，并设置代理和可编辑
    UIImagePickerController * imagePicker = [[UIImagePickerController alloc] init];
    self.imagePickerController = imagePicker;
    imagePicker.editing = YES;
    // 设置为YES则可以编辑
    [imagePicker setAllowsEditing:YES];
    // 代理，返回拍照的结果
    imagePicker.delegate = self;
    // 设置拍照返回图片的规格当然会乘以当前屏幕的倍数
    imagePicker.videoQuality = UIImagePickerControllerQualityTypeIFrame1280x720;
    //选择相机时，设置UIImagePickerController对象相关属性其实是一种依赖注入的开发模式
    //    imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    // 设置model出来的类型，因为UIImagePickController它是
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    // 社会modal出来的模式
    imagePicker.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
    imagePicker.modalPresentationStyle = UIModalPresentationFullScreen;
    
    //    imagePicker.textInputContextIdentifier = @"textInputContextIdentifier";
    //    imagePicker.cameraViewTransform = CGAffineTransformScale(imagePicker.cameraViewTransform, 0.8, 1.0);
    
    //    [imagePicker setPopoverContentSize:CGSizeMake(500, 800)];
    
    //            imagePicker.mediaTypes = @[(NSString *)kUTTypeImage];
    
    // 在 info.plist里面添加Localized resources can be mixed YES 表示是否允许应用程序获取框架库内语言。
    imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
    
    //跳转到UIImagePickerController控制器弹出相机
    if ([self.presentController isKindOfClass:[UIViewController class]] && self.presentController!= nil) {
        
        [self.presentController presentViewController:self.imagePickerController animated:YES completion:nil];
    }
}


// 判断设备是否有摄像头
- (BOOL)isCameraAvailable {
    
    return [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
}

// 前面的摄像头是否可用
- (BOOL) isFrontCameraAvailable{
    
    return [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront];
}

// 后面的摄像头是否可用
- (BOOL) isRearCameraAvailable{
    
    return [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear];
}

- (NSArray *)getCameraImageArr {
    
    NSMutableArray *mtbArr = [NSMutableArray array];
    [self enumerateObjectsUsingBlock:^(UIImage * _Nullable obj, NSUInteger idx, BOOL * _Nullable stop) {
        
        [mtbArr addObject:obj];
    } failed:^(NSError * _Nullable error) {
        
    }];
    
    return mtbArr;
}



- (void)usePhoto {
    
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        
        if (status == PHAuthorizationStatusAuthorized) { // 获取授权后得到相片
            //code
            [self getAllPhotosFromAlbum];
            
        } else {
            
            // 尚未授权或者失败
            NSError *error = [NSError errorWithDomain:@"" code:3001 userInfo:@{@"message":KUserStatusDenied}];
            self.error = error;
            self.result(nil,error);
            NSLog(@"%@",error);
        }
        
    }];
}

// 得到所有的相片
- (NSArray <UIImage *>*)getAllPhotosFromAlbum {//配置简单 ，但是参数却是比价多且
    
    // 获取权限
    self.options= [[PHImageRequestOptions alloc] init];//请求选项设置
    self.options.resizeMode=PHImageRequestOptionsResizeModeExact;
    //resizeMode  自定义设置图片的大小 枚举类型*
    // PHImageRequestOptionsResizeMode:*
    //PHImageRequestOptionsResizeModeNone = 0, //保持原size
    //PHImageRequestOptionsResizeModeFast, //高效、但不保证图片的size为自定义size
    //PHImageRequestOptionsResizeModeExact, //严格按照自定义size
    
    self.options.synchronous=YES;   //YES 一定是同步    NO不一定是异步
    
    PHImageRequestOptions *imageOptions = [PHImageRequestOptions new];
    imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact;
    /*
     PHImageRequestOptionsResizeModeNone // 不调整大小
     PHImageRequestOptionsResizeModeFast // 由系统去安排，情况不定：有时你设置的size比较低，会根据你设的size，有时又会比
     PHImageRequestOptionsResizeModeExact// 保证精确到自定义size ：此处精确的前提得用PHImageContentModeAspectFill
     */
    
    //simageOptions.version = PHImageRequestOptionsVersionCurrent;//版本 iOS8.0之后出的图片编辑extension，可以根据次枚举获取原图或者是经编辑过的图片，
    /*PHImageRequestOptionsVersion：
     PHImageRequestOptionsVersionCurrent = 0, //当前的(编辑过?经过编辑的图：原图)
     PHImageRequestOptionsVersionUnadjusted, //经过编辑的图
     PHImageRequestOptionsVersionOriginal    //原始图片
     */
    
    //    imageOptions.networkAccessAllowed = YES;//用于开启iClould中下载图片
    //    imageOptions.progressHandler   //iClould下载进度的回调
    
    
    imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;//在imageOptions.synchronous = NO的情况下最终决定是否是异步
    imageOptions.synchronous = NO;
    //容器类
    [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
    self.assets = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
    
    NSMutableArray *images = [NSMutableArray array];
    //此处option是对获取得到对 Collection 的配置  我只是把它设为nil了 可以这样使用
    /*
     //例如按资源的创建时间进行一个排序
     PHFetchOptions *options = [[PHFetchOptions alloc] init];
     //    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:nil ascending:YES];
     options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]];
     //其中：key是PHAsset类的属性   这是一个kvc
     PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
     */
    //返回一个 PHImageRequestID，在异步请求时可以根据这个ID去取消请求,同步就没办法了..
    CGSize size =CGSizeMake(375 * 2,667 * 2);
    
    // 遍历所有相片
    for (NSInteger index = 0; index < self.assets.count; index ++) {
        
        // 在这个图片里边把要处理图片的样式传入，size mode 和option这样才不会造成内存峰值
        [[PHImageManager defaultManager] requestImageForAsset:self.assets[index] targetSize:self.imageSize contentMode:PHImageContentModeDefault options:self.options resultHandler:^(UIImage*_Nullable result,NSDictionary*_Nullable info) {
            
            /*
             最终产生图片的size是有   imageOptions.resizeMode（即PHImageRequestOptions） 以及 PHImageContentMode  决定的,当然也有我们设定的size
             优先级而言
             PHImageRequestOptions > PHImageContentMode
             */
            // 这个handler 并非在主线程上执行，所以如果有UI的更新操作就得手动添加到主线程中
            // dispatch_async(dispatch_get_main_queue(), ^{ //update UI  });
#pragma If -[PHImageRequestOptions isSynchronous] returns NO (or options is nil), resultHandler may be called 1 or more times. .........异步就这个回调会调用1或多次....
#pragma If -[PHImageRequestOptions isSynchronous] returns YES, resultHandler will be called exactly once同步就1次.
            NSLog(@"%@",NSStringFromCGSize(result.size));
            //一开始本来打算是利用数据吧所有的相片先存起来的.但是发现同步会卡UI  但是异步又会被回调多次，我的数组都变成double了...只好把任务方法方法cellforItem中
            [images addObject:result];
            
        }];
    }
    
    return images;
}



#pragma mark - Deleget & DataSource
#pragma mark - UIImagePickerControllerDelegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *,id> *)editingInfo NS_DEPRECATED_IOS(2_0, 3_0) {
    
    NSLog(@"%s",__func__);
    
    
}

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
    
    // 从照相机来的照片
    UIImage *image = info[@"UIImagePickerControllerEditedImage"];
    // 从相册来的照片
    if (image == nil) {
        
        image = info[@"UIImagePickerControllerOriginalImage"];
    }
    
    
    if (self.result != nil && image != nil) {
        
        self.result(image,nil);
    }
    
    NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
 
    if([type isEqualToString:@"public.movie"]){
        //视频保存后 播放视频
        NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
        NSString *urlPath = [url path];
        if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(urlPath)) {
            UISaveVideoAtPathToSavedPhotosAlbum(urlPath, self, @selector(video:didFinishSavingWithError:contextInfo:), nil);
        }
        
    }
    
    [picker dismissViewControllerAnimated:YES completion:^{}];
    
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    
    [picker dismissViewControllerAnimated:YES completion:nil];
    
    
}

//视频保存后的回调
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    if (error) {
        NSLog(@"保存视频过程中发生错误，错误信息:%@",error.localizedDescription);
    }else{
        NSLog(@"视频保存成功.");
        //录制完之后自动播放
        NSURL *url=[NSURL fileURLWithPath:videoPath];
        self.result(url,nil);
    }
}


- (void)dealloc{
    
    NSLog(@"%s",__func__);
}

#pragma mark -  QBImagePickerControllerDelegate





@end
